﻿using Bot.Domain.DialogFlow;
using Google.Protobuf;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Bot.Domain.BotImport;
using Bot.Domain.DialogFlow.Convertor;
using Bot.Domain;
using Bot.Domain.Bot;
using Bot.Domain;
using Google.Cloud.Dialogflow.V2;
using Google.LongRunning;
using Bot.Domain.Enum;
using AutoMapper;

namespace Bot.Domain
{
    public interface IComm100BotApiService : IBotApiService
    {
    }

    public class Comm100BotApiService : IComm100BotApiService
    {
        private IDialogFlowService dialogFlowService;
        private IIntentConvertor intentConvertor;
        private IEntityConvertor entityConvertor;
        private IMapper Mapper { get; set; }

        /// <summary>
        /// type = question 时，通过question触发dialogflow的intent;type = event 时,通过 event触发dialogflow中指定的intent,
        /// </summary>
        /// <param name="bot"></param>
        /// <param name="queryIntentParameter"></param>
        /// <param name="type"></param>
        /// <param name="intentName"></param>
        /// <returns></returns>
        public async Task<DetectIntentResponseDto> ChatWithBot(BotDto bot, QueryIntentParameter queryIntentParameter, string type = "question", string intentName = "")
        {
            DetectIntentResponseDto result = new DetectIntentResponseDto();
            DetectIntentRequest request = new DetectIntentRequest();
            request.QueryInput = new Google.Cloud.Dialogflow.V2.QueryInput();
            if (type == "question")
            {
                request.QueryInput.Text = new TextInput();
                request.QueryInput.Text.Text = queryIntentParameter.question;
                request.QueryInput.Text.LanguageCode = bot.Language;
            }
            else if (type == "event" && !string.IsNullOrWhiteSpace(intentName))
            {
                string eventName = Utils.CreateMD5Hash(intentName);
                request.QueryInput.Event = new EventInput();
                request.QueryInput.Event.Name = eventName;
                request.QueryInput.Event.LanguageCode = bot.Language;
            }
            string sessionId = Convert.ToString(queryIntentParameter.sessionId);
            string dialogKey = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            DetectIntentResponseForDialogFlow responce =
                await dialogFlowService.DetectIntentAsync(dialogKey, bot.BotEngineAppId, sessionId, request);
            if (responce != null)
            {
                LogHelper.Debug(JsonConvert.SerializeObject(responce));
            }
            else
            {
                LogHelper.Debug("BotApiService.ChatWithBot responce is null");
            }
            if (responce != null && responce.responseId != null && responce.queryResult != null && responce.queryResult.intent != null)
            {
                result.intentDetectionConfidence = (decimal)responce.queryResult.intentDetectionConfidence;
                result.responseId = responce.responseId;
                result.intent = responce.queryResult.intent;
                result.intentName = result.intent.GetStringValue("displayName");
                result.allRequiredParamsPresent = responce.queryResult.allRequiredParamsPresent;
                result.fulfillmentText = responce.queryResult.fulfillmentText;
                string name = result.intent.GetStringValue("name");
                if (!string.IsNullOrWhiteSpace(name))
                {
                    string[] splitName = name.Split('/');
                    if (splitName.Length > 4)
                    {
                        result.intentId = splitName[4];
                    }
                }
                decimal intentDetectionConfidence = decimal.Multiply(result.intentDetectionConfidence, 100);
                if (type == "question" && intentDetectionConfidence < bot.HighConfidenceScore)//possible answer or no answer, delete dialogflow context
                {
                    if (responce.queryResult.outputContexts != null && responce.queryResult.outputContexts.Count > 0)
                    {
                        foreach (var context in responce.queryResult.outputContexts)
                        {
                            await dialogFlowService.DeleteContext(dialogKey, context.Name);
                        }
                    }
                }
            }
            if (responce != null && responce.queryResult != null && responce.queryResult.parameters != null)
            {
                Dictionary<string, string> parameterDic = new Dictionary<string, string>();
                foreach (var item in responce.queryResult.parameters)
                {
                    string key = item.Key;
                    string value = item.Value.ToString();
                    if (!parameterDic.ContainsKey(key))
                    {
                        parameterDic.Add(key, value);
                    }
                }

                result.Parameters = parameterDic;
            }
            return result;
        }
        public Comm100BotApiService(IDialogFlowService _dialogFlowService, IIntentConvertor _intentConvertor, IEntityConvertor _entityConvertor)
        {
            dialogFlowService = _dialogFlowService;
            intentConvertor = _intentConvertor;
            entityConvertor = _entityConvertor;
        }

        public async Task<ApiResult> GetBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult { IsSuccess = false };
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;

            Agent agent = await dialogFlowService.getAgentAsync(key, projectId);
            projectId = "";
            if (agent != null && !string.IsNullOrEmpty(agent.Parent))
            {
                int lastIndex = agent.Parent.LastIndexOf('/') + 1;
                projectId = agent.Parent.Substring(lastIndex);
                apiResult.IsSuccess = true;
                apiResult.Data = new BotModel
                {
                    BotName = agent.DisplayName,
                    Language = agent.DefaultLanguageCode,
                    ProjectId = projectId

                };
            }

            return apiResult;
        }
        public async Task DeleteEntity(BotDto bot, EntityBasicDto obj)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;

            await dialogFlowService.DeleteEntity(key, projectId, obj.MappingToBotEngine);

        }
        public async Task<string> CreateEntity(BotDto bot, EntityDto obj)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            EntityType entity = new EntityType();
            entity.Name = "";
            entityConvertor.Convert(entity, obj);

            EntityType result = await dialogFlowService.CreateEntity(key, projectId, entity, bot.Language);
            return result.Name.Split('/').LastOrDefault();
        }
        public async Task<string> EditEntity(BotDto bot, EntityDto obj)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            EntityType entity = new EntityType();
            entity.Name = string.Format("projects/{0}/agent/entityTypes/{1}", projectId, obj.MappingToBotEngine);
            entityConvertor.Convert(entity, obj);
            EntityType result = await dialogFlowService.EditEntity(key, projectId, obj.MappingToBotEngine, entity, bot.Language);
            return result.Name.Split('/').LastOrDefault();
        }
        public async Task<string> CreateBot(BotDto bot)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            string agentContent = "";

            //创建一个文件夹 里面存放 agent.json package.json 两个文件
            string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadedFiles", Guid.NewGuid().ToString());
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            var agent = Mapper.Map<agent>(bot);
            var package = new package
            {
                version = "1.0.0"
            };

            string agentPath = string.Format("{0}\\{1}.json", dir, "agent");
            string packagePath = string.Format("{0}\\{1}.json", dir, "package");

            Utils.WriteNewFile(agentPath, JsonConvert.SerializeObject(agent));
            Utils.WriteNewFile(packagePath, JsonConvert.SerializeObject(package));

            //压缩 zip
            string zipPath = Utils.Zip(dir);

            using (FileStream fs = new FileStream(zipPath, FileMode.Open))
            {
                ByteString byteString = ByteString.FromStream(fs);
                agentContent = byteString.ToBase64();

                Operation operation = await dialogFlowService.agentImportAsync(key, projectId, agentContent);
                if (operation.Done)
                {
                    return bot.BotEngineAppId;
                }
            }

            return "";
        }
        public async Task<ApiResult> TrainBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult()
            {
                IsSuccess = false
            };
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            Operation operation = await dialogFlowService.agentTrainAsync(key, projectId);
            if (operation.Done)
            {
                apiResult.IsSuccess = true;
                apiResult.Data = operation.Name;
            }
            else
            {
                if (operation.Error != null)
                {
                    apiResult.Error = new ErrorInfo(operation.Error.Message);
                }
                else
                {
                    apiResult.IsSuccess = true;
                    apiResult.Data = operation.Name;
                }
            }

            return apiResult;
        }
        public async Task<ApiResult> RestoreBot(BotDto bot, BotImportDataQueue botImportDataQueue)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            string key = Utils.GenerateDialogflowKey(botImportDataQueue.SiteId, botImportDataQueue.BotId);
            string projectId = botImportDataQueue.AppId;
            string agentContent = "";

            //压缩 zip
            string zipPath = BotImportDataQueue2Zip(botImportDataQueue);

            using (FileStream fs = new FileStream(zipPath, FileMode.Open))
            {
                ByteString byteString = ByteString.FromStream(fs);
                agentContent = byteString.ToBase64();
                LogHelper.Debug(agentContent);
                Operation operation = await dialogFlowService.agentRestoreAsync(key, projectId, agentContent);
                if (operation.Done)
                {
                    apiResult.IsSuccess = true;
                }
                else
                {
                    if (operation.Error != null)
                    {
                        apiResult.IsSuccess = false;
                        apiResult.Error = new ErrorInfo
                        {
                            Message = operation.Error.Message
                        };
                    }
                    else
                    {
                        apiResult.IsSuccess = true;
                        apiResult.Data = operation.Name;
                    }

                }

                return apiResult;
            }
        }

        public async Task<string> CreateIntent(IntentDto intent, BotDto bot)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;

            Google.Cloud.Dialogflow.V2.Intent intent_dialogflow = new Google.Cloud.Dialogflow.V2.Intent();
            intent_dialogflow.Name = "";
            intentConvertor.Convert(intent, intent_dialogflow);
            Google.Cloud.Dialogflow.V2.Intent result = await dialogFlowService.CreateIntent(key, projectId, intent_dialogflow, bot.Language);
            return result.Name.Split('/').LastOrDefault();
        }
        public async Task<string> EditIntent(IntentDto intent, BotDto bot, string MappingToBotEngine)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;

            Google.Cloud.Dialogflow.V2.Intent intent_dialogflow = new Google.Cloud.Dialogflow.V2.Intent();
            intent_dialogflow.Name = string.Format("projects/{0}/agent/intents/{1}", projectId, MappingToBotEngine);
            intentConvertor.Convert(intent, intent_dialogflow);
            Google.Cloud.Dialogflow.V2.Intent result = await dialogFlowService.EditIntent(key, projectId, MappingToBotEngine, intent_dialogflow, bot.Language);
            return result.Name.Split('/').LastOrDefault();
        }
        public async Task DeleteIntent(BotDto bot, string MappingToBotEngine)
        {
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;

            await dialogFlowService.DeleteIntent(key, projectId, MappingToBotEngine);
        }
        public async Task<bool> DeleteBot(BotDto bot)
        {
            return true;
        }
        public async Task<ApiResult> ImportBot(BotDto bot, BotImportDataQueue botImportDataQueue)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            string key = Utils.GenerateDialogflowKey(botImportDataQueue.SiteId, botImportDataQueue.BotId);
            string projectId = botImportDataQueue.AppId;
            string agentContent = "";

            //压缩 zip
            string zipPath = BotImportDataQueue2Zip(botImportDataQueue);

            using (FileStream fs = new FileStream(zipPath, FileMode.Open))
            {
                ByteString byteString = ByteString.FromStream(fs);
                agentContent = byteString.ToBase64();
                LogHelper.Debug(agentContent);
                Operation operation = await dialogFlowService.agentImportAsync(key, projectId, agentContent);
                if (operation.Done)
                {
                    apiResult.IsSuccess = true;
                }
                else
                {
                    if (operation.Error != null)
                    {
                        apiResult.IsSuccess = false;
                        apiResult.Error = new ErrorInfo
                        {
                            Message = operation.Error.Message
                        };
                    }
                    else
                    {
                        apiResult.IsSuccess = true;
                        apiResult.Data = operation.Name;
                    }

                }
            }

            return apiResult;
        }
        public async Task<ApiResult> GetOperations(BotDto bot, string operationName)
        {
            ApiResult apiResult = new ApiResult { IsSuccess = false };
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            Operation operation = await dialogFlowService.projectsOperationsGet(key, operationName);
            if (operation.Done)
            {
                apiResult.IsSuccess = true;
            }
            else
            {
                if (operation.Error != null)
                {
                    apiResult.Error = new ErrorInfo
                    {
                        Message = operation.Error.Message
                    };
                }
                else
                {
                    apiResult.IsSuccess = true;
                    apiResult.Data = operation.Name;
                }
            }

            //为了防止多次请求，延迟2s
            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));

            return apiResult;
        }
        public async Task<ApiResult> ExportBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult { };
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            Operation operation = await dialogFlowService.agentExportAsync(key, projectId);
            if (operation.Done)
            {
                apiResult.IsSuccess = true;

                ByteString byteString = operation.Response.Value;
                string unzipdir = UnzipForByteString(byteString);
                AgentExportAggregate agentExportAggregate = GetAgentExportAggregate(unzipdir);
                BotAggregate botAggregate = Mapper.Map<BotAggregate>(agentExportAggregate);
                apiResult.Data = botAggregate;
            }
            else
            {
                if (operation.Error != null)
                {
                    apiResult.IsSuccess = false;
                    apiResult.Error = new ErrorInfo
                    {
                        Message = operation.Error.Message
                    };
                }
                else
                {
                    apiResult.IsSuccess = true;
                    apiResult.Data = operation.Name;
                }
            }
            return apiResult;
        }

        /// <summary>
        /// 返回解压的Dir 
        /// </summary>
        /// <param name="byteString"></param>
        /// <returns></returns>
        private string UnzipForByteString(ByteString byteString)
        {
            using (MemoryStream ms = new MemoryStream(byteString.ToByteArray()))
            {
                string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadedFiles", Guid.NewGuid().ToString());
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

                Utils.UnZip(ms, dir);

                return dir;
            }
        }
        /// <summary>
        /// 获取解压文件夹下面的文件转成对象
        /// </summary>
        /// <param name="dir"></param>
        /// <returns></returns>
        private AgentExportAggregate GetAgentExportAggregate(string dir)
        {
            AgentExportAggregate agentExportAggregate = new AgentExportAggregate();
            string agentPath = string.Format("{0}\\agent.json", dir);
            if (File.Exists(agentPath))
            {
                string agentJson = Utils.GetFileContent(agentPath);
                agentExportAggregate.agent = JsonConvert.DeserializeObject<agent>(agentJson);
            }

            string packagePath = string.Format("{0}\\package.json", dir);
            if (File.Exists(packagePath))
            {
                string packageJson = Utils.GetFileContent(packagePath);
                agentExportAggregate.package = JsonConvert.DeserializeObject<package>(packageJson);
            }

            string intentsDir = string.Format("{0}\\intents", dir);
            string[] intentsFiles = Directory.GetFiles(intentsDir);
            string[] intentFiles = intentsFiles.Where(a => !a.Contains("_usersays_")).ToArray();
            foreach (string file in intentFiles)
            {
                string intentPath = file;
                string intentJson = Utils.GetFileContent(intentPath);
                intent intent = JsonConvert.DeserializeObject<intent>(intentJson);
                string fileName = Path.GetFileNameWithoutExtension(file);
                string usersaysPath = intentsFiles.FirstOrDefault(a => a.Contains(fileName) && a.Contains("_usersays_"));
                List<usersay> usersayList = new List<usersay>();
                if (!string.IsNullOrEmpty(usersaysPath))
                {
                    string usersaysJson = Utils.GetFileContent(usersaysPath);
                    usersayList = JsonConvert.DeserializeObject<List<usersay>>(usersaysJson);
                }

                agentExportAggregate.intentAggregateList.Add(new IntentAggregate
                {
                    intent = intent,
                    usersayList = usersayList
                });
            }

            string entitiesDir = string.Format("{0}\\entities", dir);
            string[] entitiesFiles = Directory.GetFiles(entitiesDir);
            string[] entityFiles = entitiesFiles.Where(a => !a.Contains("_entries_")).ToArray();
            foreach (string file in entityFiles)
            {
                string entityPath = file;
                string entityJson = Utils.GetFileContent(entityPath);
                entity entity = JsonConvert.DeserializeObject<entity>(entityJson);

                string fileName = Path.GetFileNameWithoutExtension(file);
                string entryPath = entitiesFiles.FirstOrDefault(a => a.Contains(fileName) && a.Contains("_entries_"));
                List<entry> entryList = new List<entry>();
                if (!string.IsNullOrEmpty(entryPath))
                {
                    string entryJson = Utils.GetFileContent(entryPath);
                    entryList = JsonConvert.DeserializeObject<List<entry>>(entryJson);
                }

                agentExportAggregate.entityAggregateList.Add(new EntityAggregate
                {
                    entity = entity,
                    entryList = entryList
                });
            }
            return agentExportAggregate;
        }
        private string BotImportDataQueue2Zip(BotImportDataQueue botImportDataQueue)
        {
            //创建一个文件夹 里面存放 agent.json package.json 两个文件
            string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadedFiles", botImportDataQueue.SiteId.ToString(), Guid.NewGuid().ToString());
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            string intentsDir = Path.Combine(dir, "intents");
            if (!Directory.Exists(intentsDir))
                Directory.CreateDirectory(intentsDir);

            string entitiesDir = Path.Combine(dir, "entities");
            if (!Directory.Exists(entitiesDir))
                Directory.CreateDirectory(entitiesDir);

            var agent = Mapper.Map<agent>(botImportDataQueue.BotImportData.Bot);
            var package = new package
            {
                version = "1.0.0"
            };

            string agentPath = string.Format("{0}\\{1}.json", dir, "agent");
            string packagePath = string.Format("{0}\\{1}.json", dir, "package");
            string lang = botImportDataQueue.BotImportData.Bot.Language;

            CreateDefaultIntentAndEntityJson(lang, intentsDir, entitiesDir);

            bool isCreateIntent = false;
            bool isCreateEntity = false;
            bool ifContainEvent = false;

            switch (botImportDataQueue.OperateType)
            {
                case EnumOperateType.importBot:
                    {
                        isCreateIntent = true;
                        isCreateEntity = true;
                        break;
                    }
                case EnumOperateType.importIntent:
                    {
                        isCreateIntent = true;
                        isCreateEntity = false;
                        break;
                    }
                case EnumOperateType.importEntity:
                    {
                        isCreateIntent = false;
                        isCreateEntity = true;
                        break;
                    }
            }

            if (isCreateIntent && botImportDataQueue.BotImportData.Bot.Category != null)
            {
                foreach (BotCategoryTypeEx category in botImportDataQueue.BotImportData.Bot.Category)
                {
                    if (category.Intent != null)
                    {
                        foreach (BotIntentTypeEx botIntent in category.Intent)
                        {
                            string name = botIntent.IntentName;

                            string pathName = Guid.NewGuid().ToString();
                            List<DialogFlow.Parameter> parameterList = new List<DialogFlow.Parameter>();

                            if (botIntent.Question != null)
                            {
                                List<usersay> usersayList = new List<usersay>();
                                foreach (BotIntentQuestionTypeEx botIntentQuestion in botIntent.Question)
                                {
                                    List<Data> dataList = new List<Data>();
                                    if (botIntentQuestion.QuestionEntity != null && botIntentQuestion.QuestionEntity.Length > 0)
                                    {
                                        string question = botIntentQuestion.Content;
                                        BotIntentQuestionEntityTypeEx[] questionEntitySortArray = botIntentQuestion.QuestionEntity.OrderBy(a => a.StartPos).ToArray();

                                        int lastPos = 0;
                                        foreach (BotIntentQuestionEntityTypeEx botIntentQuestionEntityTypeEx in questionEntitySortArray)
                                        {
                                            int startIndex = botIntentQuestionEntityTypeEx.StartPos;
                                            int length = botIntentQuestionEntityTypeEx.EndPos - botIntentQuestionEntityTypeEx.StartPos + 1;
                                           
                                            if (startIndex >= 0 && length > 0 && startIndex + length <= botIntentQuestion.Content.Length)
                                            {
                                                string dataType = "";
                                                BotEntityTypeEx botEntity = botImportDataQueue.BotImportData.Bot.Entity.FirstOrDefault(a => a.EntityName == botIntentQuestionEntityTypeEx.EntityName);
                                                if (botEntity.EntityType == BotEntityTypeEntityType.List)
                                                {
                                                    dataType = string.Format("@{0}", botIntentQuestionEntityTypeEx.EntityName);
                                                }
                                                else
                                                {
                                                    dataType = string.Format("{0}", botIntentQuestionEntityTypeEx.EntityName);
                                                }

                                                if (!parameterList.Exists(a => a.name == botIntentQuestionEntityTypeEx.EntityLabel))
                                                {
                                                    EnumEntityCollectionType collectionType = EnumEntityCollectionType.form;
                                                    bool ifViaPrompts = botIntent.IntentAnswers.Any(f => f.AnswerType == AnswerTypeType.viaPrompts);
                                                    if (ifViaPrompts)
                                                    {
                                                        if(botIntent.EntityCollectionPrompts.Any(a => a.EntityLabel == botIntentQuestionEntityTypeEx.EntityLabel))
                                                        {
                                                            collectionType = EnumEntityCollectionType.prompt;
                                                        }
                                                    }

                                                    if (/*botIntent.EntityCollectionType*/collectionType == EnumEntityCollectionType.prompt)
                                                    {
                                                        List<Prompt> promptList = new List<Prompt>();
                                                        BotEntityCollectionPromptTypeEx botEntityCollectionPromptTypeEx = botIntent.EntityCollectionPrompts.FirstOrDefault(a => a.EntityLabel == botIntentQuestionEntityTypeEx.EntityLabel);
                                                        bool required = false;
                                                        if (botEntityCollectionPromptTypeEx != null)
                                                        {
                                                            required = true;
                                                            ifContainEvent = true;
                                                            foreach (string promptQuestion in botEntityCollectionPromptTypeEx.Questions)
                                                            {
                                                                promptList.Add(new Prompt
                                                                {
                                                                    lang = lang,
                                                                    value = promptQuestion
                                                                });
                                                            }
                                                        }

                                                        //追问
                                                        parameterList.Add(new DialogFlow.Parameter
                                                        {
                                                            required = required,
                                                            dataType = dataType,
                                                            name = botIntentQuestionEntityTypeEx.EntityLabel,
                                                            value = string.Format("${0}", botIntentQuestionEntityTypeEx.EntityLabel),
                                                            prompts = promptList.ToArray(),
                                                            isList = false
                                                        });
                                                    }
                                                    else
                                                    {
                                                        parameterList.Add(new DialogFlow.Parameter
                                                        {
                                                            required = false,
                                                            dataType = dataType,
                                                            name = botIntentQuestionEntityTypeEx.EntityLabel,
                                                            value = string.Format("${0}", botIntentQuestionEntityTypeEx.EntityLabel),
                                                            isList = false
                                                        });
                                                    }
                                                }

                                                int startIndx = botIntentQuestionEntityTypeEx.StartPos - lastPos;
                                                int len = (botIntentQuestionEntityTypeEx.EndPos - lastPos) - (botIntentQuestionEntityTypeEx.StartPos - lastPos) + 1;
                                                string separator = question.Substring(startIndx, len);
                                                string preSeparator = "";

                                                if (botIntentQuestionEntityTypeEx.StartPos - lastPos > 0)
                                                {
                                                    preSeparator = question.Substring(0, botIntentQuestionEntityTypeEx.StartPos - lastPos);
                                                }

                                                if (!string.IsNullOrEmpty(preSeparator))
                                                {
                                                    dataList.Add(new Data
                                                    {
                                                        text = preSeparator,
                                                        userDefined = false
                                                    });
                                                }                                             

                                                dataList.Add(new Data
                                                {
                                                    text = separator,
                                                    alias = botIntentQuestionEntityTypeEx.EntityLabel,
                                                    meta = dataType,
                                                    userDefined = true
                                                });
                                                question = question.Substring(botIntentQuestionEntityTypeEx.EndPos - lastPos + 1);
                                                lastPos = botIntentQuestionEntityTypeEx.EndPos + 1;
                                            }
                                            else
                                            {
                                                dataList = new List<Data>();
                                                question = botIntentQuestion.Content;
                                                break;
                                            }
                                        }

                                        if (question.Length > 0)
                                        {
                                            dataList.Add(new Data
                                            {
                                                text = question,
                                                userDefined = false
                                            });
                                        }
                                    }
                                    else
                                    {
                                        dataList.Add(new Data
                                        {
                                            text = botIntentQuestion.Content,
                                            userDefined = false
                                        });
                                    }

                                    usersayList.Add(new usersay
                                    {
                                        id = "",
                                        data = dataList.ToArray(),
                                        isTemplate = false,
                                        count = 0,
                                        updated = DateTime.UtcNow
                                    });
                                }

                                string usersayJson = JsonConvert.SerializeObject(usersayList);
                                string usersayPath = string.Format("{0}/{1}_usersays_{2}.json", intentsDir, pathName, lang);
                                Utils.WriteNewFile(usersayPath, usersayJson);
                                //LogHelper.Debug(usersayPath);
                            }

                            List<Event> events = new List<Event> { };
                            if (ifContainEvent)
                            {
                                events.Add(new Event
                                {
                                    name = Utils.CreateMD5Hash(name),
                                });
                            }

                            intent intent = new intent
                            {
                                id = "",
                                name = name,
                                auto = true,
                                contexts = new string[] { },
                                responses = new DialogFlow.Response[] {
                                    new DialogFlow.Response{
                                        resetContexts=false,
                                        affectedContexts=new string[]{ },
                                        parameters=parameterList.ToArray(),
                                        messages=new DialogFlow.Message[]{
                                            new DialogFlow.Message{
                                                type=0,
                                                lang=lang,
                                                speech= new string[]{ }
                                            }
                                        },
                                        defaultResponsePlatforms=new DefaultResponsePlatforms{ },
                                        speech=new string[]{ }
                                    }
                                },
                                priority = 500000,
                                webhookUsed = false,
                                webhookForSlotFilling = false,
                                lastUpdate = DateTime.UtcNow,
                                fallbackIntent = false,
                                events = events.ToArray(),
                            };
                            string intentJson = JsonConvert.SerializeObject(intent);
                            string intentPath = string.Format("{0}/{1}.json", intentsDir, pathName);
                            Utils.WriteNewFile(intentPath, intentJson);
                            //LogHelper.Debug(intentPath);
                        }
                    }
                }
            }

            if (isCreateEntity && botImportDataQueue.BotImportData.Bot.Entity != null)
            {
                //过滤掉系统的Entity
                BotEntityTypeEx[] botEntityTypeArray = botImportDataQueue.BotImportData.Bot.Entity.Where(a => a.EntityType != BotEntityTypeEntityType.Prebuilt).ToArray();
                foreach (BotEntityTypeEx botEntity in botEntityTypeArray)
                {
                    string name = botEntity.EntityName;
                    string pathName = Guid.NewGuid().ToString();

                    entity entity = new entity
                    {
                        id = "",
                        name = name,
                        isOverridable = true,
                        isEnum = false,
                        automatedExpansion = false
                    };

                    string entityJson = JsonConvert.SerializeObject(entity);
                    string entityPath = string.Format("{0}/{1}.json", entitiesDir, pathName);
                    Utils.WriteNewFile(entityPath, entityJson);
                    //LogHelper.Debug(entityPath);

                    if (botEntity.EntityItem != null)
                    {
                        List<entry> entryList = new List<entry>();
                        foreach (BotListEntityItemTypeEx botListEntity in botEntity.EntityItem)
                        {
                            List<string> synonyms = new List<string>();
                            if (!string.IsNullOrEmpty(botListEntity.SynonymsOfKeyWord))
                            {
                                synonyms.AddRange(botListEntity.SynonymsOfKeyWord.Split(','));
                            }

                            entryList.Add(new entry
                            {
                                value = botListEntity.KeyWord,
                                synonyms = synonyms.ToArray()
                            });
                        }

                        string entryJson = JsonConvert.SerializeObject(entryList);
                        string entryPath = string.Format("{0}/{1}_entries_{2}.json", entitiesDir, pathName, lang);
                        Utils.WriteNewFile(entryPath, entryJson);
                        //LogHelper.Debug(entryPath);
                    }

                }
            }

            Utils.WriteNewFile(agentPath, JsonConvert.SerializeObject(agent));
            Utils.WriteNewFile(packagePath, JsonConvert.SerializeObject(package));

            //压缩 zip
            string zipPath = Utils.Zip(dir);
            //LogHelper.Debug(zipPath);
            return zipPath;
        }
        /// <summary>
        /// 创建一个默认的Intent和Entity，便于Restore 接口使用
        /// </summary>
        /// <param name="lang"></param>
        /// <param name="intentsDir"></param>
        /// <param name="pathName"></param>
        /// <param name="entitiesDir"></param>
        private void CreateDefaultIntentAndEntityJson(string lang, string intentsDir, string entitiesDir)
        {
            string intentName = "default";
            intent intent = new intent
            {
                id = "",
                name = intentName,
                auto = true,
                contexts = new string[] { },
                responses = new DialogFlow.Response[] {
                                    new DialogFlow.Response{
                                        resetContexts=false,
                                        affectedContexts=new string[]{ },
                                        parameters=new DialogFlow.Parameter[]{ },
                                        messages=new DialogFlow.Message[]{
                                            new DialogFlow.Message{
                                                type=0,
                                                lang=lang,
                                                speech= new string[]{ }
                                            }
                                        }
                                    }
                                },
                priority = 500000,
                webhookUsed = false,
                webhookForSlotFilling = false,
                lastUpdate = DateTime.UtcNow,
                fallbackIntent = false,
                events = new Event[] { }
            };

            string intentJson = JsonConvert.SerializeObject(intent);
            string intentPath = string.Format("{0}/{1}.json", intentsDir, intentName);
            Utils.WriteNewFile(intentPath, intentJson);

            string entityName = "default";
            entity entity = new entity
            {
                id = "",
                name = entityName,
                isOverridable = true,
                isEnum = false,
                automatedExpansion = false
            };

            string entityJson = JsonConvert.SerializeObject(entity);
            string entityPath = string.Format("{0}/{1}.json", entitiesDir, entityName);
            Utils.WriteNewFile(entityPath, entityJson);
        }

        public async Task<ApiResult> BatchDeleteIntents(BotDto bot, string[] MappingToBotEngines)
        {
            ApiResult apiResult = new ApiResult { IsSuccess = false };

            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            List<string> intent_dialogflow = new List<string>();
            foreach (string id in MappingToBotEngines)
            {
                if (!string.IsNullOrWhiteSpace(id))
                {
                    intent_dialogflow.Add(string.Format("projects/{0}/agent/intents/{1}", projectId, id));
                }
            }
            Operation result = await dialogFlowService.BatchDeleteIntents(key, projectId, intent_dialogflow.ToArray());
            if (result.Done)
            {
                apiResult.IsSuccess = true;
            }
            else
            {
                if (result.Error != null)
                {
                    apiResult.Error = new ErrorInfo
                    {
                        Message = result.Error.Message
                    };
                }
                else
                {
                    apiResult.IsSuccess = true;
                    apiResult.Data = result.Name;
                }
            }

            return apiResult;
        }
        public async Task<List<IntentModelAggregate>> GetIntentList(BotDto bot)
        {
            List<IntentModelAggregate> intentModelAggregateList = new List<IntentModelAggregate>();
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            int pageSize = 500;
            string pageToken = "";

            while (true)
            {
                SearchIntents searchIntents = await dialogFlowService.GetIntentList(key, projectId, pageSize, pageToken);
                if (searchIntents != null && searchIntents.intents != null)
                {
                    foreach (Google.Cloud.Dialogflow.V2.Intent intent in searchIntents.intents)
                    {
                        string intentId = intent.Name.Remove(0, intent.Name.LastIndexOf('/') + 1);
                        List<IntentQuestionModel> intentQuestionModelList = new List<IntentQuestionModel>();
                        if (intent.TrainingPhrases != null)
                        {
                            foreach (Google.Cloud.Dialogflow.V2.Intent.Types.TrainingPhrase trainingPhrase in intent.TrainingPhrases)
                            {
                                intentQuestionModelList.Add(new IntentQuestionModel
                                {
                                    Id = trainingPhrase.Name,
                                    Question = string.Join("", trainingPhrase.Parts.Select(a => a.Text)),
                                    IntentId = intentId,
                                    IntentName = intent.DisplayName
                                });
                            }
                        }

                        intentModelAggregateList.Add(new IntentModelAggregate
                        {
                            IntentModel = new IntentModel
                            {
                                Id = intentId,
                                IntentName = intent.DisplayName,
                                //Response = string.Join(",", intent.Messages.Select(a => a.Text))
                            },
                            IntentQuestionModelList = intentQuestionModelList
                        });
                    }
                }

                if (!string.IsNullOrEmpty(searchIntents.nextPageToken))
                {
                    pageToken = searchIntents.nextPageToken;
                }
                else
                {
                    break;
                }
            }

            return intentModelAggregateList;
        }
        public async Task<ApiResult> BatchDeleteEntities(BotDto bot, string[] MappingToBotEngines)
        {
            ApiResult apiResult = new ApiResult { IsSuccess = false };
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            string[] names = MappingToBotEngines.Select(a => string.Format("projects/{0}/agent/entityTypes/{1}", projectId, a)).ToArray();
            Operation operation = await dialogFlowService.agentEntityTypesBatchDeleteAsync(key, projectId, names);
            if (operation.Done)
            {
                apiResult.IsSuccess = true;
            }
            else
            {
                if (operation.Error != null)
                {
                    apiResult.Error = new ErrorInfo(operation.Error.Message);
                }
                else
                {
                    apiResult.IsSuccess = true;
                    apiResult.Data = operation.Name;
                }
            }
            return apiResult;
        }
        public async Task<List<EntityModelAggregate>> GetEntityList(BotDto bot)
        {
            List<EntityModelAggregate> entityModelAggregateList = new List<EntityModelAggregate>();
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            string pageToken = "";

            while (true)
            {
                SearchEntities searchEntities = await dialogFlowService.agentEntityTypesListAsync(key, projectId, pageToken);
                foreach (EntityType entityType in searchEntities.entityTypes)
                {
                    string entityId = entityType.Name.Remove(0, entityType.Name.LastIndexOf('/') + 1);
                    List<EntityKeywordModel> entityKeywordModelList = new List<EntityKeywordModel>();
                    if (entityType.Entities != null)
                    {
                        foreach (EntityType.Types.Entity entity in entityType.Entities)
                        {
                            entityKeywordModelList.Add(new EntityKeywordModel
                            {
                                EntityId = entityId,
                                EntityName = entityType.DisplayName,
                                Keyword = entity.Value,
                                Synonyms = entity.Synonyms.ToList()
                            });
                        }
                    }

                    entityModelAggregateList.Add(new EntityModelAggregate
                    {
                        EntityModel = new EntityModel
                        {
                            Id = entityId,
                            EntityName = entityType.DisplayName
                        },
                        EntityKeywordModelList = entityKeywordModelList
                    });
                }
                if (!string.IsNullOrEmpty(searchEntities.nextPageToken))
                {
                    pageToken = searchEntities.nextPageToken;
                }
                else
                {
                    break;
                }
            }

            return entityModelAggregateList;
        }

        public async Task BatchUpdateIntents(IntentDto[] intents, BotDto bot)
        {
            if (intents == null || intents.Length <= 0) return;
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            List<Google.Cloud.Dialogflow.V2.Intent> intent_dialogflow = new List<Google.Cloud.Dialogflow.V2.Intent>();
            foreach (IntentDto item in intents)
            {
                if (!string.IsNullOrWhiteSpace(item.MappingToBotEngine))
                {
                    Google.Cloud.Dialogflow.V2.Intent temp = new Google.Cloud.Dialogflow.V2.Intent();
                    temp.Name = string.Format("projects/{0}/agent/intents/{1}", projectId, item.MappingToBotEngine);
                    intentConvertor.Convert(item, temp);
                    intent_dialogflow.Add(temp);
                }
            }
            Operation result = await dialogFlowService.BatchUpdateIntents(key, projectId, intent_dialogflow.ToArray());
            if (result.Error != null)
            {
                throw new ExceptionWithCode(result.Error.Code, result.Error.Message);
            }
        }
        public async Task BatchUpdateEntities(EntityDto[] entities, BotDto bot)
        {
            if (entities == null || entities.Length <= 0) return;
            string key = Utils.GenerateDialogflowKey(bot.SiteId, bot.Id);
            string projectId = bot.BotEngineAppId;
            List<EntityType> entity_dialogflow = new List<EntityType>();
            foreach (EntityDto item in entities)
            {
                //if (!string.IsNullOrWhiteSpace(item.MappingToBotEngine))
                //{
                //    EntityType temp = new EntityType();
                //    entityConvertor.Convert(temp, item);
                //    temp.Name = string.Format("projects/{0}/agent/entityTypes/{1}", projectId, item.MappingToBotEngine);
                //    entity_dialogflow.Add(temp);
                //}
            }

            if (entity_dialogflow.Count > 0)
            {
                Operation result = await dialogFlowService.BatchUpdateEntities(key, projectId, entity_dialogflow.ToArray());
                if (result.Error != null)
                {
                    throw new ExceptionWithCode(result.Error.Code, result.Error.Message);
                }
            }
        }

        public Task<ApiResult> IdentifyEntity(BotDto bot, QueryIntentParameter queryIntentParameter, List<QuestionEntity> intentQuestionEntities)
        {
            throw new NotImplementedException();
        }
    }
}
